import os
import sys
import pty
import io
import logging
import os.path
from subprocess import Popen

from tinyops.library.helper import process_output_stream
from tinyops.notifier import NotifierManager
from tinyops.config import DirectoryManager

from .task import Task


LOG = logging.getLogger(__name__)


class TaskManager:
    def __init__(self, task: Task, output: io.FileIO = None):
        self.task = task
        self.timeout = task.timeout
        self.dm = DirectoryManager(task.config)
        notifier_factory = NotifierManager(task.config)
        self.notifier = notifier_factory.create(*task.notifier)
        self.output = output or sys.stdout
        self.current_config_filepath = self.dm.current_config()
        self.current_task_filepath = self.dm.current_task(self.task.name)
        self.logfile_path = self.dm.task_log(self.task.name)
        self.logfile = None

    def init(self):
        with open(self.current_task_filepath, 'w') as f:
            f.write(self.task.to_json())
        self.logfile = open(self.logfile_path, 'w')

    def close(self):
        if self.logfile:
            self.logfile.close()

    def _log(self, message):
        self.output.write(message)
        self.output.flush()
        if self.logfile:
            self.logfile.write(message)
            self.logfile.flush()

    def run(self):
        self.init()
        self.notifier.notify(
            f'任务 {self.task.name} 开始执行',
            '日志文件: {}'.format(self.logfile_path or '无')
        )
        try:
            cmd = [
                'tinyops', 'execute',
                '--config', self.current_config_filepath,
                '--task', self.current_task_filepath,
            ]
            master, slave = pty.openpty()
            p = Popen(cmd, stdout=slave, stderr=slave)
            os.close(slave)
            try:
                for msg in process_output_stream(master, timeout=self.timeout):
                    self._log(msg)
            finally:
                os.close(master)
                if p.poll() is None:
                    p.kill()
                p.wait()
            ok = p.returncode == 0
            if not ok:
                self._log(f'Task {self.task.name} failed, exit {p.returncode}\n')
            else:
                self._log(f'Task {self.task.name} success, exit {p.returncode}\n')
            status = '成功' if ok else '失败'
            detail = '日志文件: {}'.format(self.logfile_path or '无')
            detail += '\n```\n'
            with open(self.logfile_path) as f:
                detail += f.read()
            detail += '\n```\n'
            title = f'任务{self.task.name}执行{status}'
            if not ok:
                title = '异常@' + title
            self.notifier.notify(title, detail)
            return ok
        finally:
            self.close()
